﻿
Imports std
Imports elpmis

Namespace httpFunctions
    'parameters, o, any, convert to string, write to http response
    'return, bool, whether the write is success or not
    Public Class writeresponse
        Inherits internalFunction

        Public Class parameters
            Public Const o As String = "o"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialMapping(m, parameters.o)
        End Sub

        Public Sub New()
            MyBase.New("response.write", m)
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim o As bare_variable = Nothing
            o = ctx.findVariable(parameters.o)
            If o Is Nothing Then
                raiseError("expect parameter " + parameters.o, errorHandle.errorType.user)
                Return False
            Else
                currentContext().writer().Write(Convert.ToString(o.value()))
                output = New bare_variable(typeDefination.bool, True)
                Return True
            End If
        End Function
    End Class

    'parameters, o, a bytes instance
    'return, bool, success or not
    Public Class writeresponsebytes
        Inherits internalFunction

        Public Class parameters
            Public Const o As String = "o"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialMapping(m, parameters.o)
        End Sub

        Protected Sub New(ByVal name As String)
            MyBase.New(name, m)
        End Sub

        Public Sub New()
            Me.New("response.writebytes")
        End Sub

        Protected Overridable Sub write(ByVal bs As bytes)
            currentContext().buff().Write(+bs, 0, bs.size())
        End Sub

        Protected NotOverridable Overrides Function invoke(ByVal ctx As context, _
                                                           ByRef output As bare_variable) As Boolean
            Dim po As elpmis_pointer(Of Object) = Nothing
            Dim o As bytes = Nothing
            If Not ctx.findVariable(Of elpmis_pointer(Of Object))(parameters.o, po) OrElse _
               Not convertor.cast(Of bytes)(++po, o) Then
                If Not ctx.findVariable(Of bytes)(parameters.o, o) Then
                    raiseError("expect parameter " + parameters.o + " is an instance of bytes.", _
                               errorHandle.errorType.user)
                    Return False
                End If
            End If
            write(o)
            output = New bare_variable(typeDefination.bool, True)
            Return True
        End Function
    End Class

    'parameters, name, any, convert to string, the response header name
    '            value, any, convert to string ,the response header value
    'return, bool, whether add the response header operation is success or not
    Public Class addresponseheader
        Inherits internalFunction

        Public Class parameters
            Public Const name As String = "name"
            Public Const value As String = "value"
        End Class

        Public Sub New()
            MyBase.New("response.header.add", shared_parameters_mappings.m_name_value)
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim name As bare_variable = Nothing
            Dim value As bare_variable = Nothing
            name = ctx.findVariable(parameters.name)
            value = ctx.findVariable(parameters.value)
            If name Is Nothing OrElse value Is Nothing Then
                raiseError("expect parameters " + parameters.name + " and " + parameters.value, _
                           errorHandle.errorType.user)
                Return False
            Else
                If currentContext().addResponseHeader(Convert.ToString(name.value()), _
                                                                  Convert.ToString(value.value())) Then
                    output = New bare_variable(typeDefination.bool, True)
                Else
                    output = New bare_variable(typeDefination.bool, False)
                End If
                Return True
            End If
        End Function
    End Class

    'parameters, name, any, convert to string, the response header name
    '            value, any, convert to string ,the response header value
    'return, bool, whether overwrite the response header operation is success or not
    Public Class overwriteresponseheader
        Inherits internalFunction

        Public Class parameters
            Public Const name As String = "name"
            Public Const value As String = "value"
        End Class

        Private Shared a As aliases = Nothing

        Shared Sub New()
            initialAliases(a, "response.header.overwrite")
        End Sub

        Public Sub New()
            MyBase.New("response.header.modify", shared_parameters_mappings.m_name_value, a)
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim name As bare_variable = Nothing
            Dim value As bare_variable = Nothing
            name = ctx.findVariable(parameters.name)
            value = ctx.findVariable(parameters.value)
            If name Is Nothing OrElse value Is Nothing Then
                raiseError("expect parameters " + parameters.name + " and " + parameters.value, _
                           errorHandle.errorType.user)
                Return False
            Else
                output = New bare_variable(typeDefination.bool, _
                                           currentContext().modifyResponseHeader(Convert.ToString(name.value()), _
                                                                                 Convert.ToString(value.value())))
                Return True
            End If
        End Function
    End Class

    'parameters, name, any, convert to string, the response header name
    'return, bool, whether remove the response header operation is success or not
    Public Class removeresponseheader
        Inherits internalFunction

        Public Class parameters
            Public Const name As String = "name"
        End Class

        Public Sub New()
            MyBase.New("response.header.remove", shared_parameters_mappings.mname)
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim name As bare_variable = Nothing
            name = ctx.findVariable(parameters.name)
            If name Is Nothing Then
                raiseError("expect parameters " + parameters.name, errorHandle.errorType.user)
                Return False
            Else
                output = New bare_variable(typeDefination.bool, _
                                           currentContext().removeResponseHeader(Convert.ToString(name.value())))
                Return True
            End If
        End Function
    End Class

    'parameters, value, any, convert to string, the content type value
    'return, bool, success or not
    Public Class httpcontenttype
        Inherits internalFunction

        Public Class parameters
            Public Const value As String = "value"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialMapping(m, parameters.value)
        End Sub

        Public Sub New()
            MyBase.New("response.header.contentType", m)
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim value As String = Nothing
            If ctx.findVariableStr(parameters.value, value) Then
                output = New bare_variable(typeDefination.bool, _
                                           currentContext().setcontentType(value))
            Else
                output = New bare_variable(typeDefination.string, _
                                           currentContext().response().ContentType())
            End If
            Return True
        End Function
    End Class

    'parameters, NA
    'return, bool, success or not
    Public Class setcontenttypeOctetStream
        Inherits internalFunction

        Public Class parameters
        End Class

        Public Sub New()
            MyBase.New("response.header.contentType.octetstream")
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            output = New bare_variable(typeDefination.bool, _
                                       currentContext().modifyResponseHeader(Net.HttpResponseHeader.ContentType, _
                                                        network.http.contentType.applicationOctetStream))
            Return True
        End Function
    End Class

    'parameters, NA
    'return, bool, success or not
    Public Class setcontenttypeTextPlainUtf8
        Inherits internalFunction

        Public Class parameters
        End Class

        Public Sub New()
            MyBase.New("response.header.contentType.plainutf8")
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            output = New bare_variable(typeDefination.bool, _
                                       currentContext().modifyResponseHeader(Net.HttpResponseHeader.ContentType, _
                                                                             network.http.contentType.textplainUtf8))
            Return True
        End Function
    End Class

    'parameters, NA
    'return, bool, success or not
    Public Class setcontenttypeTextHtmlUtf8
        Inherits internalFunction

        Public Class parameters
        End Class

        Public Sub New()
            MyBase.New("response.header.contentType.htmlutf8")
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            output = New bare_variable(typeDefination.bool, _
                                       currentContext().modifyResponseHeader(Net.HttpResponseHeader.ContentType, _
                                                                             network.http.contentType.texthtmlUtf8))
            Return True
        End Function
    End Class

    'parameters, status, int, http response status code
    '            desc, optional, any, convert to string, http response status description
    'return, bool, whether set status code is success or not
    Public Class httpstatuscode
        Inherits internalFunction

        Public Class parameters
            Public Const status As String = "status"
            Public Const desc As String = "desc"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialMapping(m, parameters.status, parameters.desc)
        End Sub

        Public Sub New()
            MyBase.New("response.status", m)
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim statusv As bare_variable = Nothing
            statusv = ctx.findVariable(parameters.status)
            If statusv Is Nothing Then
                raiseError("expect parameter " + parameters.status, errorHandle.errorType.user)
                Return False
            ElseIf Not statusv.variable().isType(typeDefination.int, True) Then
                raiseError("expect parameter " + parameters.status + " is int or var.", errorHandle.errorType.user)
                Return False
            Else
                Dim status As Int64
                Try
                    status = Convert.ToInt64(statusv.value())
                Catch
                    raiseError("cannot convert parameter " + parameters.status + " to int.", errorHandle.errorType.user)
                    Return False
                End Try

                Dim desc As bare_variable = Nothing
                desc = ctx.findVariable(parameters.desc)

                Dim rtn As Boolean
                If desc Is Nothing Then
                    rtn = currentContext().setstatuscode(status)
                Else
                    rtn = currentContext().setstatuscode(status, Convert.ToString(desc.value()))
                End If

                output = New bare_variable(typeDefination.bool, rtn)
                Return True
            End If
        End Function
    End Class

    'parameters, url, any, convert to string, the destination url
    'return, bool, whether redirect success or not
    'no 30x selected in HttpListenerResponse.Redirect
    Public Class httpredirect
        Inherits internalFunction

        Public Class parameters
            Public Const url As String = "url"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialMapping(m, parameters.url)
        End Sub

        Public Sub New()
            MyBase.New("response.redirect", m)
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim url As bare_variable = Nothing
            url = ctx.findVariable(parameters.url)
            If url Is Nothing Then
                raiseError("expect parameter " + parameters.url, errorHandle.errorType.user)
                Return False
            Else
                currentContext().redirect(Convert.ToString(url.value()))
                output = New bare_variable(typeDefination.bool, True)
                Return True
            End If
        End Function
    End Class

    'parameters, name, any, convert to string, the query name
    '            value, pointer<string>/pointer<var>, the output
    'return, bool, whether found the query or not
    Public Class httprequestquery
        Inherits internalFunction

        Public Class parameters
            Public Const name As String = "name"
            Public Const value As String = "value"
        End Class

        Public Sub New()
            MyBase.New("request.query", shared_parameters_mappings.m_name_value)
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim namev As bare_variable = Nothing
            namev = ctx.findVariable(parameters.name)
            If namev Is Nothing Then
                raiseError("expect parameter " + parameters.name, errorHandle.errorType.user)
                Return False
            Else
                Dim value As bare_variable = Nothing
                value = ctx.findVariable(parameters.value)
                If value Is Nothing Then
                    raiseError("expect parameter " + parameters.value, errorHandle.errorType.user)
                    Return False
                ElseIf Not value.variable().isPointerOfString() Then
                    raiseError("expect parameter " + parameters.value + " is pointer<string>/pointer<var>.", _
                               errorHandle.errorType.user)
                    Return False
                Else
                    Dim name As String = Nothing
                    name = Convert.ToString(namev.value())
                    If currentContext().url().queryExist(name) AndAlso _
                       value.setPointerOfString(currentContext().url().query(name)) Then
                        output = New bare_variable(typeDefination.bool, True)
                    Else
                        output = New bare_variable(typeDefination.bool, False)
                    End If

                    Return True
                End If
            End If
        End Function
    End Class

    'parameters, domain, optional, any, convert to string, if not exist, use the first cookie, include path
    '            name, any, convert to string
    '            value, pointer<string>/pointer<var>, the output
    'return, bool, whether found the cookie or not
    Public Class httprequestcookie
        Inherits internalFunction

        Public Class parameters
            Public Const domain As String = "domain"
            Public Const name As String = "name"
            Public Const value As String = "value"
        End Class

        Public Sub New()
            MyBase.New("request.cookie")
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim domain As bare_variable = Nothing
            domain = ctx.findVariable(parameters.domain)
            Dim name As bare_variable = Nothing
            name = ctx.findVariable(parameters.name)
            If name Is Nothing Then
                raiseError("expect parameter " + parameters.name, errorHandle.errorType.user)
                Return False
            Else
                Dim value As bare_variable = Nothing
                value = ctx.findVariable(parameters.value)
                If value Is Nothing Then
                    raiseError("expect parameter " + parameters.value, errorHandle.errorType.user)
                    Return False
                ElseIf Not value.variable().isPointerOfString() Then
                    raiseError("expect paramter " + parameters.value + " is pointer<string>/pointer<var>.", _
                               errorHandle.errorType.user)
                    Return False
                Else
                    Dim cookie As map(Of String, String) = Nothing
                    If domain Is Nothing Then
                        cookie = currentContext().cookie()
                    Else
                        cookie = currentContext().cookie(Convert.ToString(domain.value()))
                    End If
                    If Not cookie Is Nothing Then
                        Dim it As map(Of String, String).iterator = Nothing
                        it = cookie.find(Convert.ToString(name.value()))
                        If it <> cookie.end() AndAlso value.setPointerOfString((+it).second) Then
                            output = New bare_variable(typeDefination.bool, True)
                        Else
                            output = New bare_variable(typeDefination.bool, False)
                        End If
                    Else
                        output = New bare_variable(typeDefination.bool, False)
                    End If

                    Return True
                End If
            End If
        End Function
    End Class

    'parameters, N/A
    'return, string, the request ip
    Public Class httprequestip
        Inherits noInputFunction(Of String)

        Public Class parameters
        End Class

        Public Sub New()
            MyBase.New("request.ip")
        End Sub

        Protected Overrides Function invoke(ByRef o As String) As Boolean
            o = currentContext().requestIp()
            Return True
        End Function

        Protected Overrides Function returnType() As typeDefination
            Return typeDefination.string
        End Function
    End Class

    'parameters, domain, optional, any, convert to string
    '            path, optional, any, convert to string
    '            name, any, convert to string
    '            value, any, convert to string
    '            expires, optional, any, convert to string and parse by date
    'return, bool, success or not
    Public Class httpresponsecookie
        Inherits internalFunction

        Public Class parameters
            Public Const domain As String = "domain"
            Public Const path As String = "path"
            Public Const name As String = "name"
            Public Const value As String = "value"
            Public Const expires As String = "expires"
        End Class

        Public Sub New()
            MyBase.New("response.cookie")
        End Sub

        Public Shared ReadOnly defaultExpires As UInt64 = secondsToTicks(60 * 60 * 24 * 7)

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim domain As String = Nothing
            domain = ctx.findVariableStr(parameters.domain)
            Dim path As String = Nothing
            path = ctx.findVariableStr(parameters.path)
            Dim name As String = Nothing
            If Not ctx.findVariableStr(parameters.name, name) Then
                raiseError("expect parameter " + parameters.name, errorHandle.errorType.user)
                Return False
            Else
                Dim value As String = Nothing
                If Not ctx.findVariableStr(parameters.value, value) Then
                    raiseError("expect parameter " + parameters.value, errorHandle.errorType.user)
                    Return False
                Else
                    Dim expiresStr As String = Nothing
                    expiresStr = ctx.findVariableStr(parameters.expires)
                    Dim expires As Date = Nothing
                    If isemptystring(expiresStr) OrElse Not Date.TryParse(expiresStr, expires) Then
                        expires = New Date(Now.Ticks() + defaultExpires)
                    End If
                    Dim rtn As Boolean
                    If path Is Nothing Then
                        rtn = currentContext().setcookie(name, value, expires)
                    ElseIf domain Is Nothing Then
                        rtn = currentContext().setcookie(path, name, value, expires)
                    Else
                        rtn = currentContext().setcookie(domain, path, name, value, expires)
                    End If
                    output = New bare_variable(typeDefination.bool, rtn)
                    Return True
                End If
            End If
        End Function
    End Class

    'parameters, N/A
    'return, string, the path of current request, start from /
    Public Class httprequestpath
        Inherits internalFunction

        Public Class parameters
        End Class

        Public Sub New()
            MyBase.New("request.path")
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            output = New bare_variable(typeDefination.string, currentContext().url().path())
            Return True
        End Function
    End Class

    Public Class httprequesturl
        Inherits noInputFunction(Of String)

        Public Sub New()
            MyBase.New("request.url")
        End Sub

        Protected Overrides Function invoke(ByRef o As String) As Boolean
            o = currentContext().url().full()
            Return True
        End Function

        Protected Overrides Function returnType() As typeDefination
            Return typeDefination.string
        End Function
    End Class

    Public Class requestformdata
        Inherits inputIOutputOFunction(Of String, Object)

        Public Sub New()
            MyBase.New("request.formdata")
        End Sub

        Protected Overrides Function finder() As iVariableFinder(Of String)
            Return string_finder()
        End Function

        Protected Overrides Function invoke(ByVal i As String, ByRef o As Object) As Boolean
            Dim it As map(Of String, formdata).iterator = Nothing
            it = currentContext().formdatas().find(i)
            If it <> currentContext().formdatas().end() Then
                o = (+it).second
            Else
                o = Nothing
            End If
            Return True
        End Function
    End Class

    Public Class httpresponsecontentlength
        Inherits inputIFunction(Of Int64, Object)

        Public Sub New()
            MyBase.New("response.header.contentLength")
        End Sub

        Protected Overrides Function finder() As iVariableFinder(Of Int64)
            Return int_finder()
        End Function

        Protected Overrides Function enableNoInput() As Boolean
            Return True
        End Function

        Protected Overrides Function invoke(ByVal i As Int64, ByRef o As Object) As Boolean
            If noInput() Then
                o = currentContext().response().ContentLength64()
            Else
                o = currentContext().setcontentLength64(i)
            End If
            Return True
        End Function

        Protected Overrides Function returnType() As typeDefination
            If noInput() Then
                Return typeDefination.int
            Else
                Return typeDefination.bool
            End If
        End Function
    End Class

    Public Class sendresponsebytes
        Inherits writeresponsebytes

        Public Sub New()
            MyBase.New("response.sendbytes")
        End Sub

        Protected Overrides Sub write(ByVal bs As bytes)
            currentContext().response().OutputStream().Write(+bs, 0, bs.size())
        End Sub
    End Class

    Public Class defaultcontenttype
        Inherits inputIFunction(Of String, String)

        Public Sub New()
            MyBase.new("defaultContentType")
        End Sub

        Protected Overrides Function finder() As iVariableFinder(Of String)
            Return string_finder()
        End Function

        Protected Overrides Function invoke(ByVal i As String, ByRef o As String) As Boolean
            o = getdefaultContentType(i)
            Return True
        End Function

        Protected Overrides Function returnType() As typeDefination
            Return typeDefination.string
        End Function
    End Class
End Namespace
